using Dapper_Core.Common;
using Dapper_Core.Model;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Dapper_Core.Web
{
    public class CheckSessionFilter : ActionFilterAttribute
    {
        /// <summary>
        /// 表示是否检查登陆
        /// </summary>
        public bool IsCheck { get; set; }

        /// <summary>
        /// 检查Session
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            bool ignoreCheckSession = filterContext.ActionDescriptor.FilterDescriptors
            .Select(f => f.Filter)
            .OfType<TypeFilterAttribute>()
            .Any(f => f.ImplementationType.Equals(typeof(IgnoreCheckSessionFilter)));
            if (ignoreCheckSession)
            {
                base.OnActionExecuting(filterContext);
                return;
            }

            if (IsCheck)
            {

                #region 测试不加ip_hash登录和跳转是否在不同的服务器上执行
                //object controllerObj;
                //object actionObj;
                //filterContext.RouteData.Values.TryGetValue("controller", out controllerObj);
                //filterContext.RouteData.Values.TryGetValue("action", out actionObj);
                //string address = filterContext.HttpContext.Request.HttpContext.Connection.LocalIpAddress.ToString();
                //string port = filterContext.HttpContext.Request.HttpContext.Connection.LocalPort.ToString();
                //NlogUtility.WriteInfo("CheckSessionFilter", "address=" + address + ", port=" + port, "controllerObj=" + controllerObj + ", actionObj=" + actionObj, "DapperCore");
                #endregion

                bool isInvalid = SessionUtility.GetBasicUserInfo() == null;
                if (isInvalid)
                {
                    object controllerObj;
                    object actionObj;
                    filterContext.RouteData.Values.TryGetValue("controller", out controllerObj);
                    filterContext.RouteData.Values.TryGetValue("action", out actionObj);
                    string controllerName = controllerObj == null ? string.Empty : controllerObj.ToString();
                    string actionName = actionObj == null ? string.Empty : actionObj.ToString();

                    #region 若是Api请求则无需检查Session
                    if (string.Equals(controllerName, "ADMPAccount", StringComparison.OrdinalIgnoreCase))
                    {
                        base.OnActionExecuting(filterContext);
                        return;
                    }
                    #endregion

                    bool isLoginRequest = (string.IsNullOrEmpty(controllerName) && string.IsNullOrEmpty(actionName))
                                          || (string.Equals(controllerName, "Login", StringComparison.OrdinalIgnoreCase) && string.Equals(actionName, "Index", StringComparison.OrdinalIgnoreCase));
                    bool isAjaxRequest = filterContext.HttpContext.Request.IsAjaxRequest();
                    if (isAjaxRequest)
                    {
                        //filterContext.Result = new RedirectToRouteResult(new { Controller = "Login", action = "Index", TimeOutPage = "/Login/Index" });
                        filterContext.Result = new RedirectResult("/Login/Index");
                    }
                    else
                    {
                        //filterContext.Result = new RedirectToRouteResult(new { Controller = "Login", action = "Index", TimeOutPage = "/Login/Index", IsToOutView = true, isLoginRequest = isLoginRequest });
                        filterContext.Result = new RedirectResult("/Login/Index");
                    }
                }
                else
                {
                    if (HasPermission(filterContext))
                    {
                        base.OnActionExecuting(filterContext);
                    }
                    else
                    {
                        filterContext.Result = new RedirectResult("/Login/NoPermission");
                    }
                }
            }
            else
            {
                base.OnActionExecuting(filterContext);
            }
        }

        private bool HasPermission(ActionExecutingContext filterContext)
        {
            //Ajax请求不做权限控制
            if (filterContext.HttpContext.Request.IsAjaxRequest()) return true;
            //非Ajax请求用户必须登录且有权访问才行
            List<string> pageUrls = SessionUtility.GetSessionData<List<string>>(SessionKey.GetAllMenuPageUrlsKey());
            if (pageUrls == null || pageUrls.Count == 0) return false;

            object areaObj;
            filterContext.RouteData.Values.TryGetValue("area", out areaObj);
            string currentUrl = filterContext.HttpContext.Request.GetDisplayUrl();
            currentUrl = currentUrl.Substring(currentUrl.IndexOf("/", 8));
            if (currentUrl.Contains("?")) currentUrl = currentUrl.Substring(currentUrl.IndexOf("?", 8));
            if (currentUrl.Length - currentUrl.Replace("/", "").Length > 1 + Convert.ToInt32(areaObj != null))
            {
                #region 前提：配置时Controller、Action不能省略，处理没省略Controller、Action的请求
                //请求与配置相同
                if (pageUrls.Where(pageUrl => string.Equals(pageUrl, currentUrl, StringComparison.OrdinalIgnoreCase)).Count() > 0) return true;
                //请求（/home/Index/1）比配置（/home/Index）长
                if (pageUrls.Where(pageUrl => currentUrl.StartsWith(pageUrl + "/", StringComparison.OrdinalIgnoreCase)).Count() > 0) return true;
                //请求（/home/Index）比配置（/home/Index/1）短
                if (pageUrls.Where(pageUrl => pageUrl.StartsWith(currentUrl + "/", StringComparison.OrdinalIgnoreCase)).Count() > 0) return true;
                //请求（/home/Index）比配置（/home/Index?id=1）短
                if (pageUrls.Where(pageUrl => pageUrl.StartsWith(currentUrl + "?", StringComparison.OrdinalIgnoreCase)).Count() > 0) return true;
                #endregion
            }
            else
            {
                #region 前提：配置时Controller、Action不能省略，处理省略Controller、Action的请求
                string areaControllerAction = GetAreacontrolleraction(filterContext);
                //请求与配置相同
                if (pageUrls.Where(pageUrl => string.Equals(pageUrl, areaControllerAction, StringComparison.OrdinalIgnoreCase)).Count() > 0) return true;
                //请求（/home/Index）比配置（/home）长
                if (pageUrls.Where(pageUrl => areaControllerAction.StartsWith(pageUrl + "/", StringComparison.OrdinalIgnoreCase)).Count() > 0) return true;
                //请求（/home/Index）比配置（/home/Index/1）短
                if (pageUrls.Where(pageUrl => pageUrl.StartsWith(areaControllerAction + "/", StringComparison.OrdinalIgnoreCase)).Count() > 0) return true;
                //请求（/home/Index）比配置（/home/Index?id=1）短
                if (pageUrls.Where(pageUrl => pageUrl.StartsWith(areaControllerAction + "?", StringComparison.OrdinalIgnoreCase)).Count() > 0) return true;
                #endregion
            }

            return false;
        }

        private string GetAreacontrolleraction(ActionExecutingContext filterContext)
        {
            string uri = "";
            object areaObj;
            object controllerObj;
            object actionObj;
            filterContext.RouteData.Values.TryGetValue("area", out areaObj);
            filterContext.RouteData.Values.TryGetValue("controller", out controllerObj);
            filterContext.RouteData.Values.TryGetValue("action", out actionObj);
            if (areaObj != null)
            {
                uri += "/" + areaObj.ToString();
            }
            if (controllerObj != null)
            {
                uri += "/" + controllerObj.ToString();
            }
            if (actionObj != null)
            {
                uri += "/" + actionObj.ToString();
            }
            return uri;
        }
    }
}
